From 2b1110a91de576080578d772cfdc82bc38ec4777 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C3=98yvind=20Kol=C3=A5s?= Date: Tue, 16 Aug 2005 07:38:22 +0000 Subject: [PATCH] added CIE Lab and YCbCr models --- ChangeLog | 24 ++ babl/babl-fish.c | 10 +- babl/babl-ids.h | 11 +- babl/base/Makefile.am | 9 +- babl/base/babl-base.c | 5 + babl/base/cpercep.c | 652 ++++++++++++++++++++++++++++++++++++ babl/base/cpercep.h | 70 ++++ babl/base/model-cmyk.c | 135 ++++++-- babl/base/model-lab.c | 197 +++++++++++ babl/base/model-rgb.c | 2 +- babl/base/model-ycbcr.c | 139 +++++++- babl/base/type-u16.c | 2 +- tests/Makefile.am | 16 +- tests/rgb_to_lab_to_rgb.c | 99 ++++++ tests/rgb_to_ycbcr.c | 101 ++++++ tests/rgb_to_ycbcr_to_rgb.c | 98 ++++++ 16 files changed, 1523 insertions(+), 47 deletions(-) create mode 100644 babl/base/cpercep.c create mode 100644 babl/base/cpercep.h create mode 100644 babl/base/model-lab.c create mode 100644 tests/rgb_to_lab_to_rgb.c create mode 100644 tests/rgb_to_ycbcr.c create mode 100644 tests/rgb_to_ycbcr_to_rgb.c diff --git a/ChangeLog b/ChangeLog index 0e461a3..ed4f524 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2005-08-16 Øyvind Kolås + + * babl/babl-fish.c: reindentation, no naming of fishes. + * babl/babl-ids.h: reordering, added YCBCRA, LAB and LAB_ALPHA + * babl/base/Makefile.am: added cpercep.[ch] model-lab.c and + model-ycbcr.c + * babl/base/cpercep.[ch]: *NEW* + * babl/base/model-lab.c: *NEW* CIE Lab color model, backed by a slightly + modified version of cpercep from gimp sources (no gamma correction and + normalized RGB values) + * babl/base/model-ycbcr: made ycbcr work, numbers still need to be + verified. + * babl/base/babl-base.c: initialize CIE Lab and YCbCr + * babl/base/model-cmyk.c: slight changes, it still doesn't pass + rgb->cmyk->rgb testing so not included yet. + * babl/base/model-rgb.c: make rgba-double use BABL_DOUBLE instead of + BABL_FLOAT + * babl/base/type-u16: fix conversion to double. + * tests/Makefile.am: added rgb_to_lab_to_rgb , rgb_to_ycbcr_to_rgb and + rgb_to_ycbcr + * tests/rgb_to_lab_to_rgb.c + * tests/rgb_to_ycbcr_to_rgb.c + * tests/rgb_to_ycbcr.c: *NEW* tests + 2005-08-15 Øyvind Kolås * babl/base/model-cmyk.c diff --git a/babl/babl-fish.c b/babl/babl-fish.c index 0e376af..d8d4a8a 100644 --- a/babl/babl-fish.c +++ b/babl/babl-fish.c @@ -100,15 +100,16 @@ BablConversion *babl_conversion_find (Babl *source, Babl *destination) { SearchData data; - data.source = source; + data.source = source; data.destination = destination; - data.result = NULL; + data.result = NULL; babl_conversion_each (find_conversion, &data); if (!data.result) { - babl_log ("%s('%s', '%s'): failed", __FUNCTION__, + babl_log ("%s('%s', '%s'): failed, aborting", __FUNCTION__, source->instance.name, destination->instance.name); + exit (-1); return NULL; } return data.result; @@ -126,7 +127,7 @@ babl_fish_reference_new (Babl *source, babl = babl_calloc (sizeof (BablFishReference), 1); babl->class_type = BABL_FISH_REFERENCE; babl->instance.id = 0; - babl->instance.name = "Fishy"; + babl->instance.name = NULL; babl->fish.source = (union Babl*)source; babl->fish.destination = (union Babl*)destination; @@ -203,6 +204,7 @@ babl_fish_process (BablFish *babl_fish, fooA = babl_malloc(sizeof (double) * n * 4); fooB = babl_malloc(sizeof (double) * n * 4); + assert (babl_fish); assert (source); assert (destination); diff --git a/babl/babl-ids.h b/babl/babl-ids.h index 84656b3..9f6f331 100644 --- a/babl/babl-ids.h +++ b/babl/babl-ids.h @@ -64,14 +64,17 @@ enum { BABL_RGBA, BABL_RGBA_GAMMA_2_2, BABL_RGBA_PREMULTIPLIED, - BABL_CMY, - BABL_CMYK, - BABL_CMYKA, - BABL_YCBCR, BABL_GRAYSCALE, BABL_GRAYSCALE_GAMMA_2_2, BABL_GRAYSCALE_ALPHA, BABL_GRAYSCALE_ALPHA_PREMULTIPLIED, + BABL_YCBCR, + BABL_YCBCRA, + BABL_LAB, + BABL_LAB_ALPHA, + BABL_CMY, + BABL_CMYK, + BABL_CMYKA, BABL_PIXEL_FORMAT_BASE = 100000, BABL_SRGB, diff --git a/babl/base/Makefile.am b/babl/base/Makefile.am index c31d8a5..9014777 100644 --- a/babl/base/Makefile.am +++ b/babl/base/Makefile.am @@ -1,14 +1,18 @@ h_sources = \ - babl-base.h + babl-base.h \ + cpercep.h c_sources = \ babl-base.c \ + cpercep.c \ type-double.c \ type-float.c \ type-u8.c \ type-u16.c \ model-rgb.c \ - model-grayscale.c + model-grayscale.c \ + model-lab.c \ + model-ycbcr.c INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/babl @@ -19,6 +23,5 @@ EXTRA_DIST := \ .cvsignore \ rgb-constants.h \ util.h - LDADD = -lm diff --git a/babl/base/babl-base.c b/babl/base/babl-base.c index 8d4ea7e..68050cd 100644 --- a/babl/base/babl-base.c +++ b/babl/base/babl-base.c @@ -64,6 +64,8 @@ types (void) void babl_base_model_rgb (void); void babl_base_model_grayscale (void); +void babl_base_model_ycbcr (void); +void babl_base_model_lab (void); static void models (void) @@ -71,4 +73,7 @@ models (void) babl_base_model_rgb (); /* must be registered first since it is the reference */ babl_base_model_grayscale (); + babl_base_model_lab (); + babl_base_model_ycbcr (); } + diff --git a/babl/base/cpercep.c b/babl/base/cpercep.c new file mode 100644 index 0000000..055bf95 --- /dev/null +++ b/babl/base/cpercep.c @@ -0,0 +1,652 @@ +/* +Copyright (C) 1999-2002 Adam D. Moss (the "Author"). All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- +NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the Author of the +Software shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written authorization +from the Author. +*/ + +/* + cpercep.c: The CPercep Functions v0.9: 2002-02-10 + Adam D. Moss: adam@gimp.org + + This code module concerns itself with conversion from a hard-coded + RGB colour space (sRGB by default) to CIE L*a*b* and back again with + (primarily) precision and (secondarily) speed, oriented largely + towards the purposes of quantifying the PERCEPTUAL difference between + two arbitrary RGB colours with a minimum of fuss. + + Motivation One: The author is disheartened at the amount of graphics + processing software around which uses weighted or non-weighted + Euclidean distance between co-ordinates within a (poorly-defined) RGB + space as the basis of what should really be an estimate of perceptual + difference to the human eye. Certainly it's fast to do it that way, + but please think carefully about whether your particular application + should be tolerating sloppy results for the sake of real-time response. + + Motivation Two: Lack of tested, re-usable and free code available + for this purpose. The difficulty in finding something similar to + CPercep with a free license motivated this project; I hope that this + code also serves to illustrate how to perform the + R'G'B'->XYZ->L*a*b*->XYZ->R'G'B' transformation correctly since I + was distressed to note how many of the equations and code snippets + on the net were omitting the reverse transform and/or were using + incorrectly-derived or just plain wrong constants. + + TODO: document functions, rename erroneously-named arguments +*/ + +/* defines added to make it compile outside gimp */ + +#ifndef gboolean +#define gboolean int +#endif +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +#include "config.h" +#include + +#ifndef __GLIBC__ +/* cbrt() is a GNU extension */ +#define cbrt(x) (pow(x, 1.0/3.0)) +#endif + +#include "cpercep.h" + + +/* defines: + + SANITY: emits warnings when passed non-sane colours (and usually + corrects them) -- useful when debugging. + + APPROX: speeds up the conversion from RGB to the colourspace by + assuming that the RGB values passed in are integral and definitely + in the range 0->255 + + SRGB: assumes that the RGB values being passed in (and out) are + destined for an sRGB-alike display device (a typical modern monitor) + -- if you change this then you'll probably want to change ASSUMED_GAMMA, + the phosphor colours and the white point definition. +*/ + +/* #define SANITY */ +/* #define APPROX */ +/* #define SRGB */ + + +#ifdef SRGB +#define ASSUMED_GAMMA (2.2F) +#else +/*#define ASSUMED_GAMMA (2.591F)*/ +#define ASSUMED_GAMMA (1.0F) +#endif + +#define REV_GAMMA ((1.0F / ASSUMED_GAMMA)) + + +/* define characteristics of the source RGB space (and the space + within which we try to behave linearly). */ + +/* Phosphor colours: */ + +/* sRGB/HDTV phosphor colours */ +static const double pxr = 0.64F; +static const double pyr = 0.33F; +static const double pxg = 0.30F; +static const double pyg = 0.60F; +static const double pxb = 0.15F; +static const double pyb = 0.06F; + +/* White point: */ + +/* D65 (6500K) (recommended but not a common display default) */ +static const double lxn = 0.312713F; +static const double lyn = 0.329016F; + +/* D50 (5000K) */ +/*static const double lxn = 0.3457F; */ +/*static const double lyn = 0.3585F; */ + +/* D55 (5500K) */ +/*static const double lxn = 0.3324F; */ +/*static const double lyn = 0.3474F; */ + +/* D93 (9300K) (a common monitor default, but poor colour reproduction) */ +/* static const double lxn = 0.2848F; */ +/* static const double lyn = 0.2932F; */ + +/* illum E (normalized) */ +/*static const double lxn = 1.0/3.0F; */ +/*static const double lyn = 1.0/3.0F; */ + +/* illum C (average sunlight) */ +/*static const double lxn = 0.3101F; */ +/*static const double lyn = 0.3162F; */ + +/* illum B (direct sunlight) */ +/*static const double lxn = 0.3484F; */ +/*static const double lyn = 0.3516F; */ + +/* illum A (tungsten lamp) */ +/*static const double lxn = 0.4476F; */ +/*static const double lyn = 0.4074F; */ + + +static const double LRAMP = 7.99959199F; + + +static double xnn, znn; + +static double powtable[256]; + + +#ifndef CLAMP +#define CLAMP(x,l,u) ((x)<(l)?(l):((x)>(u)?(u):(x))) +#endif + + +static void +init_powtable(const double gamma) +{ + int i; + +#ifndef SRGB + /* pure gamma function */ + for (i=0; i<256; i++) + { + powtable[i] = pow((i)/255.0F, gamma); + } +#else + /* sRGB gamma curve */ + for (i=0; i<11 /* 0.03928 * 255 */; i++) + { + powtable[i] = (i) / (255.0F * 12.92F); + } + for (; i<256; i++) + { + powtable[i] = pow( (((i) / 255.0F) + 0.055F) / 1.055F, 2.4F); + } +#endif +} + + +typedef double CMatrix[3][3]; +typedef double CVector[3]; + +static CMatrix Mrgb_to_xyz, Mxyz_to_rgb; + +static int +Minvert (CMatrix src, CMatrix dest) +{ + double det; + + dest[0][0] = src[1][1] * src[2][2] - src[1][2] * src[2][1]; + dest[0][1] = src[0][2] * src[2][1] - src[0][1] * src[2][2]; + dest[0][2] = src[0][1] * src[1][2] - src[0][2] * src[1][1]; + dest[1][0] = src[1][2] * src[2][0] - src[1][0] * src[2][2]; + dest[1][1] = src[0][0] * src[2][2] - src[0][2] * src[2][0]; + dest[1][2] = src[0][2] * src[1][0] - src[0][0] * src[1][2]; + dest[2][0] = src[1][0] * src[2][1] - src[1][1] * src[2][0]; + dest[2][1] = src[0][1] * src[2][0] - src[0][0] * src[2][1]; + dest[2][2] = src[0][0] * src[1][1] - src[0][1] * src[1][0]; + + det = + src[0][0] * dest[0][0] + + src[0][1] * dest[1][0] + + src[0][2] * dest[2][0]; + + if (det <= 0.0F) + { +#ifdef SANITY + g_printerr ("\n\007 XXXX det: %f\n", det); +#endif + return 0; + } + + dest[0][0] /= det; + dest[0][1] /= det; + dest[0][2] /= det; + dest[1][0] /= det; + dest[1][1] /= det; + dest[1][2] /= det; + dest[2][0] /= det; + dest[2][1] /= det; + dest[2][2] /= det; + + return 1; +} + + +static void +rgbxyzrgb_init(void) +{ + init_powtable (ASSUMED_GAMMA); + + xnn = lxn / lyn; + /* ynn taken as 1.0 */ + znn = (1.0F - (lxn + lyn)) / lyn; + + { + CMatrix MRC, MRCi; + double C1,C2,C3; + + MRC[0][0] = pxr; + MRC[0][1] = pxg; + MRC[0][2] = pxb; + MRC[1][0] = pyr; + MRC[1][1] = pyg; + MRC[1][2] = pyb; + MRC[2][0] = 1.0F - (pxr + pyr); + MRC[2][1] = 1.0F - (pxg + pyg); + MRC[2][2] = 1.0F - (pxb + pyb); + + Minvert (MRC, MRCi); + + C1 = MRCi[0][0]*xnn + MRCi[0][1] + MRCi[0][2]*znn; + C2 = MRCi[1][0]*xnn + MRCi[1][1] + MRCi[1][2]*znn; + C3 = MRCi[2][0]*xnn + MRCi[2][1] + MRCi[2][2]*znn; + + Mrgb_to_xyz[0][0] = MRC[0][0] * C1; + Mrgb_to_xyz[0][1] = MRC[0][1] * C2; + Mrgb_to_xyz[0][2] = MRC[0][2] * C3; + Mrgb_to_xyz[1][0] = MRC[1][0] * C1; + Mrgb_to_xyz[1][1] = MRC[1][1] * C2; + Mrgb_to_xyz[1][2] = MRC[1][2] * C3; + Mrgb_to_xyz[2][0] = MRC[2][0] * C1; + Mrgb_to_xyz[2][1] = MRC[2][1] * C2; + Mrgb_to_xyz[2][2] = MRC[2][2] * C3; + + Minvert (Mrgb_to_xyz, Mxyz_to_rgb); + } +} + + +static void +xyz_to_rgb (double *inx_outr, + double *iny_outg, + double *inz_outb) +{ + const double x = *inx_outr; + const double y = *iny_outg; + const double z = *inz_outb; + + *inx_outr = Mxyz_to_rgb[0][0]*x + Mxyz_to_rgb[0][1]*y + Mxyz_to_rgb[0][2]*z; + *iny_outg = Mxyz_to_rgb[1][0]*x + Mxyz_to_rgb[1][1]*y + Mxyz_to_rgb[1][2]*z; + *inz_outb = Mxyz_to_rgb[2][0]*x + Mxyz_to_rgb[2][1]*y + Mxyz_to_rgb[2][2]*z; +} + + +static void +rgb_to_xyz (double *inr_outx, + double *ing_outy, + double *inb_outz) +{ + const double r = *inr_outx; + const double g = *ing_outy; + const double b = *inb_outz; + + *inr_outx = Mrgb_to_xyz[0][0]*r + Mrgb_to_xyz[0][1]*g + Mrgb_to_xyz[0][2]*b; + *ing_outy = Mrgb_to_xyz[1][0]*r + Mrgb_to_xyz[1][1]*g + Mrgb_to_xyz[1][2]*b; + *inb_outz = Mrgb_to_xyz[2][0]*r + Mrgb_to_xyz[2][1]*g + Mrgb_to_xyz[2][2]*b; +} + + +static inline double +ffunc(const double t) +{ + if (t > 0.008856F) + { + return (cbrt(t)); + } + else + { + return (7.787F * t + 16.0F/116.0F); + } +} + + +static inline double +ffunc_inv(const double t) +{ + if (t > 0.206893F) + { + return (t * t * t); + } + else + { + return ((t - 16.0F/116.0F) / 7.787F); + } +} + + +static void +xyz_to_lab (double *inx, + double *iny, + double *inz) +{ + double L,a,b; + double ffuncY; + const double X = *inx; + const double Y = *iny; + const double Z = *inz; + + if (Y > 0.0F) + { + if (Y > 0.008856F) + { + L = (116.0F * cbrt(Y)) - 16.0F; + } + else + { + L = (Y * 903.3F); + } + +#ifdef SANITY + if (L < 0.0F) + { + g_printerr (" %f \007",(float)L); + } + + if (L > 100.0F) + { + g_printerr (" %f \007",(float)L); + } +#endif + } + else + { + L = 0.0; + } + + ffuncY = ffunc(Y); + a = 500.0F * (ffunc(X/xnn) - ffuncY); + b = 200.0F * (ffuncY - ffunc(Z/znn)); + + *inx = L; + *iny = a; + *inz = b; +} + + +static void +lab_to_xyz (double *inl, + double *ina, + double *inb) +{ + double X,Y,Z; + double P; + const double L = *inl; + const double a = *ina; + const double b = *inb; + + if (L > LRAMP) + { + P = Y = (L + 16.0F) / 116.0F; + Y = Y * Y * Y; + } + else + { + Y = L / 903.3F; + P = 7.787F * Y + 16.0F/116.0F; + } + + X = (P + a / 500.0F); + X = xnn * ffunc_inv(X); + Z = (P - b / 200.0F); + Z = znn * ffunc_inv(Z); + +#ifdef SANITY + if (X<-0.00000F) + { + if (X<-0.0001F) + g_printerr ("{badX %f {%f,%f,%f}}",X,L,a,b); + X = 0.0F; + } + if (Y<-0.00000F) + { + if (Y<-0.0001F) + g_printerr ("{badY %f}",Y); + Y = 0.0F; + } + if (Z<-0.00000F) + { + if (Z<-0.1F) + g_printerr ("{badZ %f}",Z); + Z = 0.0F; + } +#endif + + *inl = X; + *ina = Y; + *inb = Z; +} + + + +/* call this before using the CPercep function */ +void +cpercep_init (void) +{ + static gboolean initialized = FALSE; + + if (! initialized) + { + rgbxyzrgb_init(); + initialized = TRUE; + } +} + +void +cpercep_rgb_to_space (double inr, + double ing, + double inb, + double *outr, + double *outg, + double *outb) +{ +#ifdef APPROX +#ifdef SANITY + /* ADM extra sanity */ + if ((inr) > 255.0F || + (ing) > 255.0F || + (inb) > 255.0F || + (inr) < -0.0F || + (ing) < -0.0F || + (inb) < -0.0F + ) + abort(); +#endif /* SANITY */ + inr = powtable[(int)inr]; + ing = powtable[(int)ing]; + inb = powtable[(int)inb]; +#else +#ifdef SRGB + /* sRGB gamma curve */ + if (inr <= (0.03928F * 255.0F)) + inr = inr / (255.0F * 12.92F); + else + inr = pow( (inr + (0.055F * 255.0F)) / (1.055F * 255.0F), 2.4F); + + if (ing <= (0.03928F * 255.0F)) + ing = ing / (255.0F * 12.92F); + else + ing = pow( (ing + (0.055F * 255.0F)) / (1.055F * 255.0F), 2.4F); + + if (inb <= (0.03928F * 255.0F)) + inb = inb / (255.0F * 12.92F); + else + inb = pow( (inb + (0.055F * 255.0F)) / (1.055F * 255.0F), 2.4F); +#else + /* pure gamma function */ + + /* babl uses normalized RGB + inr = pow((inr)/255.0F, ASSUMED_GAMMA); + ing = pow((ing)/255.0F, ASSUMED_GAMMA); + inb = pow((inb)/255.0F, ASSUMED_GAMMA); + */ +#endif /* SRGB */ +#endif /* APPROX */ + +#ifdef SANITY + /* ADM extra sanity */ + if ((inr) > 1.0F || + (ing) > 1.0F || + (inb) > 1.0F || + (inr) < 0.0F || + (ing) < 0.0F || + (inb) < 0.0F + ) + { + g_printerr ("%%"); + /* abort(); */ + } +#endif /* SANITY */ + + rgb_to_xyz(&inr, &ing, &inb); + +#ifdef SANITY + if (inr < 0.0F || ing < 0.0F || inb < 0.0F) + { + g_printerr (" [BAD2 XYZ: %f,%f,%f]\007 ", + inr,ing,inb); + } +#endif /* SANITY */ + + xyz_to_lab(&inr, &ing, &inb); + + *outr = inr; + *outg = ing; + *outb = inb; +} + + +void +cpercep_space_to_rgb (double inr, + double ing, + double inb, + double *outr, + double *outg, + double *outb) +{ + lab_to_xyz(&inr, &ing, &inb); + +#ifdef SANITY + if (inr<-0.0F || ing<-0.0F || inb<-0.0F) + { + g_printerr (" [BAD1 XYZ: %f,%f,%f]\007 ", + inr,ing,inb); + } +#endif + + xyz_to_rgb(&inr, &ing, &inb); + + /* yes, essential. :( */ + inr = CLAMP(inr,0.0F,1.0F); + ing = CLAMP(ing,0.0F,1.0F); + inb = CLAMP(inb,0.0F,1.0F); + +#ifdef SRGB + if (inr <= 0.0030402477F) + inr = inr * (12.92F * 255.0F); + else + inr = pow(inr, 1.0F/2.4F) * (1.055F * 255.0F) - (0.055F * 255.0F); + + if (ing <= 0.0030402477F) + ing = ing * (12.92F * 255.0F); + else + ing = pow(ing, 1.0F/2.4F) * (1.055F * 255.0F) - (0.055F * 255.0F); + + if (inb <= 0.0030402477F) + inb = inb * (12.92F * 255.0F); + else + inb = pow(inb, 1.0F/2.4F) * (1.055F * 255.0F) - (0.055F * 255.0F); +#else + /* babl uses normalized RGB values + inr = 255.0F * pow(inr, REV_GAMMA); + ing = 255.0F * pow(ing, REV_GAMMA); + inb = 255.0F * pow(inb, REV_GAMMA); + */ +#endif + + *outr = inr; + *outg = ing; + *outb = inb; +} + + +#if 0 +/* EXPERIMENTAL SECTION */ + +const double +xscaler(const double start, const double end, + const double me, const double him) +{ + return start + ((end-start) * him) / (me + him); +} + + +void +mix_colours (const double L1, const double a1, const double b1, + const double L2, const double a2, const double b2, + double *rtnL, double *rtna, double *rtnb, + double mass1, double mass2) +{ + double w1, w2; + +#if 0 + *rtnL = xscaler (L1, L2, mass1, mass2); + *rtna = xscaler (a1, a2, mass1, mass2); + *rtnb = xscaler (b1, b2, mass1, mass2); +#else + +#if 1 + w1 = mass1 * L1; + w2 = mass2 * L2; +#else + w1 = mass1 * (L1*L1*L1); + w2 = mass2 * (L2*L2*L2); +#endif + + *rtnL = xscaler (L1, L2, mass1, mass2); + + if (w1 <= 0.0 && + w2 <= 0.0) + { + *rtna = + *rtnb = 0.0; +#ifdef SANITY + /* g_printerr ("\007OUCH. "); */ +#endif + } + else + { + *rtna = xscaler(a1, a2, w1, w2); + *rtnb = xscaler(b1, b2, w1, w2); + } +#endif +} +#endif /* EXPERIMENTAL SECTION */ diff --git a/babl/base/cpercep.h b/babl/base/cpercep.h new file mode 100644 index 0000000..82bc5c0 --- /dev/null +++ b/babl/base/cpercep.h @@ -0,0 +1,70 @@ +/* +Copyright (C) 1997-2002 Adam D. Moss (the "Author"). All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- +NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the Author of the +Software shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written authorization +from the Author. +*/ + +/* + cpercep.c: The CPercep Functions v0.9: 2002-02-10 + Adam D. Moss: adam@gimp.org + + TODO: document functions, rename erroneously-named arguments +*/ + +#ifndef __CPERCEP_H__ +#define __CPERCEP_H__ + + +void cpercep_init (void); + +void cpercep_rgb_to_space (double inr, + double ing, + double inb, + double *outr, + double *outg, + double *outb); + +void cpercep_space_to_rgb (double inr, + double ing, + double inb, + double *outr, + double *outg, + double *outb); + + +#if 0 +/* This is in the header so that it can potentially be inlined. */ +static const double +cpercep_distance_space (const double L1, const double a1, const double b1, + const double L2, const double a2, const double b2) +{ + const double Ld = L1 - L2; + const double ad = a1 - a2; + const double bd = b1 - b2; + + return (Ld*Ld + ad*ad + bd*bd); +} +#endif + + +#endif /* __CPERCEP_H__ */ diff --git a/babl/base/model-cmyk.c b/babl/base/model-cmyk.c index d74f3fc..4c10122 100644 --- a/babl/base/model-cmyk.c +++ b/babl/base/model-cmyk.c @@ -95,6 +95,110 @@ models (void) ); } +static void +rgb_to_cmyk (int src_bands, + void **src, + int *src_pitch, + int dst_bands, + void **dst, + int *dst_pitch, + int n) +{ + BABL_PLANAR_SANITY + + while (n--) + { + double red = *(double*)src[0]; + double green = *(double*)src[1]; + double blue = *(double*)src[2]; + + double cyan, magenta, yellow, key; + + double pullout = 1.0; + + cyan = 1.0 - red; + magenta = 1.0 - green; + yellow = 1.0 - blue; + + key = 1.0; + if (cyan < key) key = cyan; + if (magenta < key) key = magenta; + if (yellow < key) key = yellow; + + key *= pullout; + + if (key < 1.0) + { + cyan = (cyan - key) / (1.0 -key); + magenta = (magenta - key) / (1.0 -key); + yellow = (yellow - key) / (1.0 -key); + } + else + { + cyan = 0.0; + magenta = 0.0; + yellow = 0.0; + } + + *(double*)dst[0] = cyan; + *(double*)dst[1] = magenta; + *(double*)dst[2] = yellow; + *(double*)dst[3] = key; + + if (dst_bands > 4) /* alpha passthorugh */ + *(double*)dst[4] = (src_bands>3)?*(double*)src[3]:1.0; + + BABL_PLANAR_STEP + } +} + +static void +cmyk_to_rgb (int src_bands, + void **src, + int *src_pitch, + int dst_bands, + void **dst, + int *dst_pitch, + int n) +{ + BABL_PLANAR_SANITY + + while (n--) + { + double cyan = *(double*)src[0]; + double yellow = *(double*)src[1]; + double magenta = *(double*)src[2]; + double key = *(double*)src[3]; + + double red, green, blue; + + if (key < 1.0) + { + cyan = cyan * (1.0 - key) + key; + magenta = magenta * (1.0 - key) + key; + yellow = yellow * (1.0 - key) + key; + } + else + { + cyan = magenta = yellow = 1.0; + } + + red = 1.0 - cyan; + green = 1.0 - magenta; + blue = 1.0 - yellow; + + *(double*)dst[0] = red; + *(double*)dst[1] = green; + *(double*)dst[2] = blue; + + if (dst_bands > 3) /* alpha passthorugh */ + *(double*)dst[3] = (src_bands>4)?*(double*)src[4]:1.0; + + BABL_PLANAR_STEP + } +} + +#if 0 static void rgb_to_and_from_cmy (int src_bands, void **src, @@ -124,6 +228,7 @@ rgb_to_and_from_cmy (int src_bands, BABL_PLANAR_STEP } } +#endif static void conversions (void) @@ -131,17 +236,17 @@ conversions (void) babl_conversion_new ( "babl-base: rgba to cmy", "source", babl_model_id (BABL_RGBA), - "destination", babl_model_id (BABL_CMY), - "planar", rgb_to_and_from_cmy, + "destination", babl_model_id (BABL_CMYK), + "planar", rgb_to_cmyk, NULL ); babl_conversion_new ( "babl-base: cmy to rgba", - "source", babl_model_id (BABL_CMY), + "source", babl_model_id (BABL_CMYK), "destination", babl_model_id (BABL_RGBA), - "planar", rgb_to_and_from_cmy, + "planar", cmyk_to_rgb, NULL ); } @@ -149,27 +254,5 @@ conversions (void) static void pixel_formats (void) { - babl_pixel_format_new ( - "cmyk-float", - "id", BABL_CMYK_FLOAT, - babl_model_id (BABL_CMYK), - babl_type_id (BABL_FLOAT), - babl_component_id (BABL_CYAN), - babl_component_id (BABL_MAGENTA), - babl_component_id (BABL_YELLOW), - babl_component_id (BABL_KEY), - NULL); - - babl_pixel_format_new ( - "cmyka-float", - "id", BABL_CMYKA_FLOAT, - babl_model_id (BABL_CMYKA), - babl_type_id (BABL_FLOAT), - babl_component_id (BABL_CYAN), - babl_component_id (BABL_MAGENTA), - babl_component_id (BABL_YELLOW), - babl_component_id (BABL_KEY), - babl_component_id (BABL_ALPHA), - NULL); } diff --git a/babl/base/model-lab.c b/babl/base/model-lab.c new file mode 100644 index 0000000..f08cf9d --- /dev/null +++ b/babl/base/model-lab.c @@ -0,0 +1,197 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "babl.h" +#include "util.h" +#include "cpercep.h" + +static void components (void); +static void models (void); +static void conversions (void); +static void pixel_formats (void); + +void +babl_base_model_lab (void) +{ + cpercep_init (); + components (); + models (); + conversions (); + pixel_formats (); +} + +static void +components (void) +{ + babl_component_new ( + "L", + "id", BABL_LAB_L, + "luma", + NULL); + + babl_component_new ( + "a", + "id", BABL_LAB_A, + "chroma", + NULL); + + babl_component_new ( + "b", + "id", BABL_LAB_B, + "chroma", + NULL); +} + +static void +models (void) +{ + babl_model_new ( + "CIE Lab", + "id", BABL_LAB, + babl_component_id (BABL_LAB_L), + babl_component_id (BABL_LAB_A), + babl_component_id (BABL_LAB_B), + NULL); + + babl_model_new ( + "CIE Lab alpha", + "id", BABL_LAB_ALPHA, + babl_component_id (BABL_LAB_L), + babl_component_id (BABL_LAB_A), + babl_component_id (BABL_LAB_B), + babl_component_id (BABL_ALPHA), + NULL); +} + +static void +rgb_to_lab (int src_bands, + void **src, + int *src_pitch, + int dst_bands, + void **dst, + int *dst_pitch, + int n) +{ + BABL_PLANAR_SANITY + + while (n--) + { + double red = *(double*)src[0]; + double green = *(double*)src[1]; + double blue = *(double*)src[2]; + + double L, a, b; + + cpercep_rgb_to_space (red, green, blue, &L, &a, &b); + + *(double*)dst[0] = L; + *(double*)dst[1] = a; + *(double*)dst[2] = b; + + if (dst_bands > 3) /* alpha passthorugh */ + *(double*)dst[3] = (src_bands>3)?*(double*)src[3]:1.0; + + BABL_PLANAR_STEP + } +} + +static void +lab_to_rgb (int src_bands, + void **src, + int *src_pitch, + int dst_bands, + void **dst, + int *dst_pitch, + int n) +{ + BABL_PLANAR_SANITY + + while (n--) + { + double L = *(double*)src[0]; + double a = *(double*)src[1]; + double b = *(double*)src[2]; + + double red, green, blue; + + cpercep_space_to_rgb (L, a, b, &red, &green, &blue); + + *(double*)dst[0] = red; + *(double*)dst[1] = green; + *(double*)dst[2] = blue; + + if (dst_bands > 3) /* alpha passthorugh */ + *(double*)dst[3] = (src_bands>3)?*(double*)src[3]:1.0; + + BABL_PLANAR_STEP + } +} + +static void +conversions (void) +{ + babl_conversion_new ( + "babl-base: rgba to lab", + "source", babl_model_id (BABL_RGBA), + "destination", babl_model_id (BABL_LAB), + "planar", rgb_to_lab, + NULL + ); + babl_conversion_new ( + "babl-base: lab to rgba", + "source", babl_model_id (BABL_LAB), + "destination", babl_model_id (BABL_RGBA), + "planar", lab_to_rgb, + NULL + ); + babl_conversion_new ( + "babl-base: rgb to lab", + "source", babl_model_id (BABL_RGB), + "destination", babl_model_id (BABL_LAB), + "planar", rgb_to_lab, + NULL + ); + babl_conversion_new ( + "babl-base: lab to rgb", + "source", babl_model_id (BABL_LAB), + "destination", babl_model_id (BABL_RGB), + "planar", lab_to_rgb, + NULL + ); + babl_conversion_new ( + "babl-base: rgba to laba", + "source", babl_model_id (BABL_RGBA), + "destination", babl_model_id (BABL_LAB_ALPHA), + "planar", rgb_to_lab, + NULL + ); + babl_conversion_new ( + "babl-base: laba to rgba", + "source", babl_model_id (BABL_LAB_ALPHA), + "destination", babl_model_id (BABL_RGBA), + "planar", lab_to_rgb, + NULL + ); +} + +static void +pixel_formats (void) +{ +} diff --git a/babl/base/model-rgb.c b/babl/base/model-rgb.c index c143558..8d5f28d 100644 --- a/babl/base/model-rgb.c +++ b/babl/base/model-rgb.c @@ -420,7 +420,7 @@ pixel_formats (void) "rgba-double", "id", BABL_RGBA_DOUBLE, babl_model_id (BABL_RGBA), - babl_type_id (BABL_FLOAT), + babl_type_id (BABL_DOUBLE), babl_component_id (BABL_RED), babl_component_id (BABL_GREEN), babl_component_id (BABL_BLUE), diff --git a/babl/base/model-ycbcr.c b/babl/base/model-ycbcr.c index 093247f..feb0d58 100644 --- a/babl/base/model-ycbcr.c +++ b/babl/base/model-ycbcr.c @@ -41,14 +41,14 @@ babl_base_model_ycbcr (void) static void components (void) { - babl_component_new ( - "Cb", + babl_component_new ( + "cb", "id", BABL_CB, "chroma", NULL); babl_component_new ( - "Cr", + "cr", "id", BABL_CR, "chroma", NULL); @@ -57,11 +57,144 @@ components (void) static void models (void) { + babl_model_new ( + "ycbcr", + "id", BABL_YCBCR, + babl_component_id (BABL_LUMINANCE), + babl_component_id (BABL_CB), + babl_component_id (BABL_CR), + NULL); + + babl_model_new ( + "ycbcra", + "id", BABL_YCBCRA, + babl_component_id (BABL_LUMINANCE), + babl_component_id (BABL_CB), + babl_component_id (BABL_CR), + babl_component_id (BABL_ALPHA), + NULL); +} + +static void +rgb_to_ycbcr (int src_bands, + void **src, + int *src_pitch, + int dst_bands, + void **dst, + int *dst_pitch, + int n) +{ + BABL_PLANAR_SANITY + + while (n--) + { + double red = *(double*)src[0]; + double green = *(double*)src[1]; + double blue = *(double*)src[2]; + + double luminance, cb, cr; + + luminance = 0.299 * red + + 0.587 * green + + 0.114 * blue; + cb = (-0.1687) * red + -0.3313 * green + + 0.5 * blue; + cr = 0.5 * red + -0.4187 * green + + -0.0813 * blue; + + *(double*)dst[0] = luminance; + *(double*)dst[1] = cb; + *(double*)dst[2] = cr; + + if (dst_bands > 3) /* alpha passthorugh */ + *(double*)dst[3] = (src_bands>3)?*(double*)src[3]:1.0; + + BABL_PLANAR_STEP + } +} + +static void +ycbcr_to_rgb (int src_bands, + void **src, + int *src_pitch, + int dst_bands, + void **dst, + int *dst_pitch, + int n) +{ + BABL_PLANAR_SANITY + + while (n--) + { + double luminance = *(double*)src[0]; + double cb = *(double*)src[1]; + double cr = *(double*)src[2]; + + double red, green, blue; + + red = luminance + 1.40200 * cr; + green = luminance - 0.34414 * cb - 0.71414 *cr; + blue = luminance + 1.77200 * cb; + + + *(double*)dst[0] = red; + *(double*)dst[1] = green; + *(double*)dst[2] = blue; + + if (dst_bands > 3) /* alpha passthorugh */ + *(double*)dst[3] = (src_bands>3)?*(double*)src[3]:1.0; + + BABL_PLANAR_STEP + } } static void conversions (void) { + babl_conversion_new ( + "babl-base: rgba to ycbcr", + "source", babl_model_id (BABL_RGBA), + "destination", babl_model_id (BABL_YCBCR), + "planar", rgb_to_ycbcr, + NULL + ); + babl_conversion_new ( + "babl-base: ycbcr to rgba", + "source", babl_model_id (BABL_YCBCR), + "destination", babl_model_id (BABL_RGBA), + "planar", ycbcr_to_rgb, + NULL + ); + babl_conversion_new ( + "babl-base: rgb to ycbcr", + "source", babl_model_id (BABL_RGB), + "destination", babl_model_id (BABL_YCBCR), + "planar", rgb_to_ycbcr, + NULL + ); + babl_conversion_new ( + "babl-base: ycbcr to rgb", + "source", babl_model_id (BABL_YCBCR), + "destination", babl_model_id (BABL_RGB), + "planar", ycbcr_to_rgb, + NULL + ); + babl_conversion_new ( + "babl-base: rgba to ycbcra", + "source", babl_model_id (BABL_RGBA), + "destination", babl_model_id (BABL_YCBCRA), + "planar", rgb_to_ycbcr, + NULL + ); + babl_conversion_new ( + "babl-base: ycbcra to rgba", + "source", babl_model_id (BABL_YCBCRA), + "destination", babl_model_id (BABL_RGBA), + "planar", ycbcr_to_rgb, + NULL + ); } static void diff --git a/babl/base/type-u16.c b/babl/base/type-u16.c index 2b602b0..f1850f0 100644 --- a/babl/base/type-u16.c +++ b/babl/base/type-u16.c @@ -51,7 +51,7 @@ convert_u16_double (void *src, { while (n--) { - (*(double *) dst) = (*(unsigned short *) src*65535.0); + (*(double *) dst) = (*(unsigned short *) src / 65535.0); dst += 8; src += 2; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 081b449..6774d7d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,11 +1,17 @@ TESTS = \ float_to_u8 \ grayscale_to_rgb \ - u8_to_float - -float_to_u8_SOURCES = float_to_u8.c -u8_to_float_SOURCES = u8_to_float.c -grayscale_to_rgb_SOURCES = grayscale_to_rgb.c + u8_to_float \ + rgb_to_lab_to_rgb \ + rgb_to_ycbcr \ + rgb_to_ycbcr_to_rgb + +float_to_u8_SOURCES = float_to_u8.c +u8_to_float_SOURCES = u8_to_float.c +grayscale_to_rgb_SOURCES = grayscale_to_rgb.c +rgb_to_lab_to_rgb_SOURCES = rgb_to_lab_to_rgb.c +rgb_to_ycbcr_SOURCES = rgb_to_ycbcr.c +rgb_to_ycbcr_to_rgb_SOURCES = rgb_to_ycbcr_to_rgb.c AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/babl diff --git a/tests/rgb_to_lab_to_rgb.c b/tests/rgb_to_lab_to_rgb.c new file mode 100644 index 0000000..063a9fe --- /dev/null +++ b/tests/rgb_to_lab_to_rgb.c @@ -0,0 +1,99 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include +#include "babl.h" +#include "babl-internal.h" + +#define PIXELS 6 +#define TOLERANCE 0.001 + +float source_buf [PIXELS*3]= + {0.0, 0.0, 0.0, + 0.5, 0.5, 0.5, + 1.0, 1.0, 1.0, + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0}; + +float temp_buf [PIXELS*3]; +float destination_buf [PIXELS*3]; + +int +test (void) +{ + BablFish *fish; + int i; + int OK=1; + + + fish = babl_fish ( + (Babl*) babl_pixel_format_new ( + "foo", + babl_model ("rgb"), + babl_type ("float"), + babl_component ("red"), + babl_component ("green"), + babl_component ("blue"), + NULL + ), + (Babl*) babl_pixel_format_new ( + "bar", + babl_model ("CIE Lab"), + babl_type ("float"), + babl_component ("L"), + babl_component ("a"), + babl_component ("b"), + NULL + ) + ); + + babl_fish_process (fish, source_buf, temp_buf, PIXELS); + + fish = babl_fish ((Babl*) babl_pixel_format ("bar"), + (Babl*) babl_pixel_format ("foo")); + + babl_fish_process (fish, temp_buf, destination_buf, PIXELS); + + for (i=0; i TOLERANCE) + { + babl_log ("%2i (%2i%%3=%i, %2i/3=%i) is %f should be %f", + i, i,i%3, i,i/3, destination_buf[i], source_buf[i]); + OK=0; + } + } + + if (!OK) + return -1; + return 0; +} + +int +main (int argc, + char **argv) +{ + babl_init (); + if (test()) + return -1; + babl_destroy (); + return 0; +} diff --git a/tests/rgb_to_ycbcr.c b/tests/rgb_to_ycbcr.c new file mode 100644 index 0000000..4cbef79 --- /dev/null +++ b/tests/rgb_to_ycbcr.c @@ -0,0 +1,101 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include +#include "babl.h" +#include "babl-internal.h" + +#define PIXELS 6 +#define TOLERANCE 0.000001 + +float source_buf [PIXELS*3]= + {0.0, 0.0, 0.0, + 0.5, 0.5, 0.5, + 1.0, 1.0, 1.0, + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0}; + +float reference_buf [PIXELS*3]= + {0.0, 0.0, 0.0, + 0.5, 0.0, 0.0, + 1.0, 0.0, 0.0, + 0.299,-0.1687, 0.5, + 0.587,-0.3313,-0.4187, + 0.114, 0.5, -0.081300}; + + +float destination_buf [PIXELS*3]; + +int +test (void) +{ + BablFish *fish; + int i; + int OK=1; + + + fish = babl_fish ( + (Babl*) babl_pixel_format_new ( + "foo", + babl_model ("rgb"), + babl_type ("float"), + babl_component ("red"), + babl_component ("green"), + babl_component ("blue"), + NULL + ), + (Babl*) babl_pixel_format_new ( + "bar", + babl_model ("ycbcr"), + babl_type ("float"), + babl_component ("luminance"), + babl_component ("cb"), + babl_component ("cr"), + NULL + ) + ); + + babl_fish_process (fish, source_buf, destination_buf, PIXELS); + + for (i=0; i TOLERANCE) + { + babl_log ("%2i (%2i%%3=%i, %2i/3=%i) is %f should be %f", + i, i,i%3, i,i/3, destination_buf[i], reference_buf[i]); + OK=0; + } + } + if (!OK) + return -1; + return 0; +} + +int +main (int argc, + char **argv) +{ + babl_init (); + if (test()) + return -1; + babl_destroy (); + return 0; +} diff --git a/tests/rgb_to_ycbcr_to_rgb.c b/tests/rgb_to_ycbcr_to_rgb.c new file mode 100644 index 0000000..d78ecb5 --- /dev/null +++ b/tests/rgb_to_ycbcr_to_rgb.c @@ -0,0 +1,98 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include +#include "babl.h" +#include "babl-internal.h" + +#define PIXELS 6 +#define TOLERANCE 0.001 + +float source_buf [PIXELS*3]= + {0.0, 0.0, 0.0, + 0.5, 0.5, 0.5, + 1.0, 1.0, 1.0, + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0}; + +float temp_buf [PIXELS*3]; +float destination_buf [PIXELS*3]; + +int +test (void) +{ + BablFish *fish; + int i; + int OK=1; + + + fish = babl_fish ( + (Babl*) babl_pixel_format_new ( + "foo", + babl_model ("rgb"), + babl_type ("float"), + babl_component ("red"), + babl_component ("green"), + babl_component ("blue"), + NULL + ), + (Babl*) babl_pixel_format_new ( + "bar", + babl_model ("ycbcr"), + babl_type ("float"), + babl_component ("luminance"), + babl_component ("cb"), + babl_component ("cr"), + NULL + ) + ); + + babl_fish_process (fish, source_buf, temp_buf, PIXELS); + + fish = babl_fish ((Babl*) babl_pixel_format ("bar"), + (Babl*) babl_pixel_format ("foo")); + + babl_fish_process (fish, temp_buf, destination_buf, PIXELS); + + for (i=0; i TOLERANCE) + { + babl_log ("%2i (%2i%%3=%i, %2i/3=%i) is %f should be %f", + i, i,i%3, i,i/3, destination_buf[i], source_buf[i]); + OK=0; + } + } + if (!OK) + return -1; + return 0; +} + +int +main (int argc, + char **argv) +{ + babl_init (); + if (test()) + return -1; + babl_destroy (); + return 0; +} -- 2.30.2